#include "stdafx.h"
#include "MiniImplFactory.h"
#include "MiniBasicImpl.h"
#include "GlobalVariables.h"
#include <new>

MiniImplFactory::MiniImplFactory() : refCount(1)
{
    InterlockedIncrement(&globalRefCount);
}

MiniImplFactory::~MiniImplFactory()
{
    InterlockedDecrement(&globalRefCount);
}

// IUnknown
STDMETHODIMP MiniImplFactory::QueryInterface(REFIID iid, LPVOID* ppData)
{
    HRESULT hr = S_OK;
    if(ppData)
    {
        if(iid == IID_IUnknown)
        {
            *ppData = static_cast<IUnknown*>(this);
        }
        else if(iid == IID_IClassFactory)
        {
            *ppData = static_cast<IClassFactory*>(this);
        }
        else
        {
            *ppData = NULL;
            hr = E_NOINTERFACE;
        }
        if(*ppData)
        {
            AddRef();
        }
    }
    else
    {
        hr = E_POINTER;
    }
    return hr;
}

STDMETHODIMP_(ULONG) MiniImplFactory::AddRef()
{
    return InterlockedIncrement(&refCount);
}

STDMETHODIMP_(ULONG) MiniImplFactory::Release()
{
    LONG count = InterlockedDecrement(&refCount);
    if(count == 0)
    {
        delete this;
    }
    return count;
}

STDMETHODIMP MiniImplFactory::CreateInstance(IUnknown *pUnk, const IID &riid, LPVOID *ppv)
{
    HRESULT hr = S_OK;
    if(ppv)
    {
        if(!pUnk)
        {
            if(riid == IID_IMiniBasic || riid == IID_IUnknown)
            {
                try
                {
                    *ppv = new (std::nothrow) MiniBasicImpl;
                    if(!*ppv)
                    {
                        hr = E_OUTOFMEMORY;
                    }
                }
                catch(const std::runtime_error&)
                {
                    hr = E_FAIL;
                }
            }
            else
            {
                hr = E_NOINTERFACE;
            }
        }
        else
        {
            hr = CLASS_E_NOAGGREGATION;
        }
    }
    else
    {
        hr = E_POINTER;
    }
    return hr;
}